import socket
import sys
import threading
import json
import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog, messagebox
import base64
from datetime import datetime
from PIL import Image, ImageTk, ImageDraw, ImageFont
import io
import os
import platform


class ChatClient:
    def __init__(self):
        self.socket = None
        self.username = ""
        self.room = "general"
        self.connected = False

        # 创建主窗口
        self.root = tk.Tk()
        self.root.title("简易聊天室")
        self.root.geometry("940x632")
        self.set_app_icon()
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.emojis = ["😀", "😂", "🥰", "😍", "😭", "😡", "👍", "👎", "❤️", "💙", "🎉", "🔥", "🌟", "🎈", "🎊", "💯"]

        self.emoji_images = {}
        # self.create_emoji_images()

        self.setup_emoji_font()

        self.chat_images = []  # 存储聊天中的原始图片数据

        self.setup_ui()
        self.set_windows_app_user_model_id()

    def set_app_icon(self):
        """设置应用图标为对话（支持 .ico/.png，放置在 assets/ 目录）"""
        try:
            base_dir = os.path.dirname(os.path.abspath(__file__))
            assets_dir = os.path.join(base_dir, 'assets')
            ico_path = os.path.join(assets_dir, '对话.ico')
            png_path = os.path.join(assets_dir, '对话.png')

            # Windows 优先使用 .ico
            if os.path.exists(ico_path):
                try:
                    self.root.iconbitmap(default=ico_path)
                    return
                except Exception:
                    pass

            # 其他平台或 .ico 失败时尝试 .png
            if os.path.exists(png_path):
                try:
                    img = tk.PhotoImage(file=png_path)
                    # 需要保存引用避免被回收
                    self._app_icon_image = img
                    self.root.iconphoto(True, img)
                    return
                except Exception:
                    pass
        except Exception:
            pass

    def set_windows_app_user_model_id(self):
        """在 Windows 上设置 AppUserModelID，便于任务栏显示自定义图标与分组"""
        try:
            if sys.platform.startswith('win'):
                import ctypes
                app_id = u"DBTool.DogIcon.1.0"
                ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
        except Exception:
            pass
    def setup_emoji_font(self):
        """设置支持彩色表情的字体"""
        system = platform.system()
        if system == "Windows":
            # Windows系统使用Segoe UI Emoji
            self.emoji_font = ("Segoe UI Emoji", 14)
            self.emoji_button_font = ("Segoe UI Emoji", 12)
        elif system == "Darwin":  # macOS
            # macOS使用Apple Color Emoji
            self.emoji_font = ("Apple Color Emoji", 14)
            self.emoji_button_font = ("Apple Color Emoji", 12)
        else:  # Linux
            # Linux尝试使用Noto Color Emoji或回退到默认
            self.emoji_font = ("Noto Color Emoji", 14, "normal")
            self.emoji_button_font = ("Noto Color Emoji", 12, "normal")

    def setup_ui(self):
        """设置用户界面"""
        # 连接框架
        connect_frame = ttk.Frame(self.root)
        connect_frame.pack(fill=tk.X, padx=10, pady=5)

        ttk.Label(connect_frame, text="用户名:").pack(side=tk.LEFT)
        self.username_entry = ttk.Entry(connect_frame, width=15)
        self.username_entry.pack(side=tk.LEFT, padx=5)

        ttk.Label(connect_frame, text="房间:").pack(side=tk.LEFT, padx=(20, 0))
        self.room_entry = ttk.Entry(connect_frame, width=15)
        self.room_entry.pack(side=tk.LEFT, padx=5)
        self.room_entry.insert(0, "general")

        ttk.Label(connect_frame, text="服务器:").pack(side=tk.LEFT, padx=(20, 0))
        self.server_entry = ttk.Entry(connect_frame, width=15)
        self.server_entry.pack(side=tk.LEFT, padx=5)
        self.server_entry.insert(0, "localhost:12345")

        self.connect_btn = ttk.Button(connect_frame, text="连接", command=self.connect_to_server)
        self.connect_btn.pack(side=tk.LEFT, padx=10)

        self.refresh_users_btn = ttk.Button(connect_frame, text="刷新用户列表", command=self.refresh_user_list)
        self.refresh_users_btn.pack(side=tk.LEFT, padx=5)
        self.refresh_users_btn.config(state=tk.DISABLED)  # 初始状态为禁用

        self.save_chat_btn = ttk.Button(connect_frame, text="保存聊天记录", command=self.save_chat_history)
        self.save_chat_btn.pack(side=tk.LEFT, padx=5)
        self.save_chat_btn.config(state=tk.DISABLED)  # 初始状态为禁用

        # 主要内容区域
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 左侧：聊天区域
        chat_frame = ttk.Frame(main_frame)
        chat_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        mode_frame = ttk.LabelFrame(chat_frame, text="聊天模式")
        mode_frame.pack(fill=tk.X, pady=(0, 5))

        mode_inner_frame = ttk.Frame(mode_frame)
        mode_inner_frame.pack(fill=tk.X, padx=5, pady=5)

        self.chat_mode = tk.StringVar(value="group")
        ttk.Radiobutton(mode_inner_frame, text="群聊", variable=self.chat_mode, value="group",
                        command=self.on_chat_mode_change).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(mode_inner_frame, text="私聊", variable=self.chat_mode, value="private",
                        command=self.on_chat_mode_change).pack(side=tk.LEFT, padx=5)

        # 私聊目标用户选择
        self.private_target_frame = ttk.Frame(mode_inner_frame)
        ttk.Label(self.private_target_frame, text="私聊对象:").pack(side=tk.LEFT, padx=(20, 5))
        self.private_target_var = tk.StringVar()
        self.private_target_combo = ttk.Combobox(self.private_target_frame, textvariable=self.private_target_var,
                                                 width=15, state="readonly")
        self.private_target_combo.pack(side=tk.LEFT, padx=5)

        self.chat_status_var = tk.StringVar()
        self.chat_status_var.set("群聊模式")
        self.chat_status_label = ttk.Label(mode_inner_frame, textvariable=self.chat_status_var, foreground="blue",
                                           font=("Arial", 9, "italic"))
        self.chat_status_label.pack(side=tk.RIGHT, padx=10)

        # 消息显示区域
        self.message_area = scrolledtext.ScrolledText(
            chat_frame,
            state=tk.DISABLED,
            wrap=tk.WORD,
            height=20,
            font=("Arial", 10)
        )
        self.message_area.pack(fill=tk.BOTH, expand=True)

        input_frame = ttk.Frame(chat_frame)
        input_frame.pack(fill=tk.X, pady=(5, 0))

        # 消息输入框
        entry_frame = ttk.Frame(input_frame)
        entry_frame.pack(fill=tk.X, pady=(0, 5))

        self.message_entry = ttk.Entry(entry_frame)
        self.message_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
        self.message_entry.bind("<Return>", self.send_message)
        self.message_entry.bind("<Control-Return>", lambda e: self.message_entry.insert(tk.INSERT, '\n'))

        # 发送按钮组
        button_frame = ttk.Frame(entry_frame)
        button_frame.pack(side=tk.RIGHT, padx=(5, 0))

        ttk.Button(button_frame, text="发送", command=self.send_message).pack(side=tk.TOP, pady=(0, 2))
        ttk.Button(button_frame, text="图片", command=self.send_image).pack(side=tk.TOP)

        emoji_frame = ttk.LabelFrame(input_frame, text="表情包")
        emoji_frame.pack(fill=tk.X, pady=(5, 0))

        emoji_grid = ttk.Frame(emoji_frame)
        emoji_grid.pack(padx=5, pady=5)

        # 分两行显示表情包，每行8个
        for i, emoji in enumerate(self.emojis):
            row = i // 8
            col = i % 8

            if emoji in self.emoji_images:
                btn = tk.Button(
                    emoji_grid,
                    image=self.emoji_images[emoji],
                    width=32,
                    height=32,
                    relief=tk.RAISED,
                    bd=1,
                    command=lambda e=emoji: self.send_emoji(e),
                    cursor="hand2"
                )
            else:
                btn = tk.Button(
                    emoji_grid,
                    text=emoji,
                    font=self.emoji_button_font,
                    width=3,
                    height=1,
                    relief=tk.RAISED,
                    bd=1,
                    command=lambda e=emoji: self.send_emoji(e),
                    cursor="hand2"
                )
            btn.grid(row=row, column=col, padx=1, pady=1)

        user_frame = ttk.LabelFrame(main_frame, text="在线用户", width=200)
        user_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(10, 0))
        user_frame.pack_propagate(False)

        # 用户列表操作提示
        user_tip_frame = ttk.Frame(user_frame)
        user_tip_frame.pack(fill=tk.X, padx=5, pady=(5, 0))

        tip_label = ttk.Label(user_tip_frame, text="双击用户名开始私聊", font=("Arial", 8), foreground="gray")
        tip_label.pack()

        self.user_listbox = tk.Listbox(user_frame, font=("Arial", 10))
        self.user_listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        self.user_listbox.bind("<Double-Button-1>", self.on_user_double_click)

        self.user_count_var = tk.StringVar()
        self.user_count_var.set("在线用户: 0")
        user_count_label = ttk.Label(user_frame, textvariable=self.user_count_var, font=("Arial", 8), foreground="gray")
        user_count_label.pack(pady=(0, 5))

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("未连接")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.pack(fill=tk.X, side=tk.BOTTOM)

    def connect_to_server(self):
        """连接到服务器"""
        if self.connected:
            self.disconnect_from_server()
            return

        username = self.username_entry.get().strip()
        room = self.room_entry.get().strip()
        server_info = self.server_entry.get().strip()

        if not username:
            messagebox.showerror("错误", "请输入用户名")
            return

        if not room:
            room = "general"

        try:
            host, port = server_info.split(':')
            port = int(port)
        except:
            messagebox.showerror("错误", "服务器地址格式错误 (例: localhost:12345)")
            return

        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((host, port))

            self.username = username
            self.room = room
            self.connected = True

            # 发送加入消息
            join_message = {
                'type': 'join',
                'username': username,
                'room': room
            }
            self.send_to_server(join_message)

            # 启动接收线程
            receive_thread = threading.Thread(target=self.receive_messages)
            receive_thread.daemon = True
            receive_thread.start()

            # 更新UI
            self.connect_btn.config(text="断开")
            self.refresh_users_btn.config(state=tk.NORMAL)
            self.save_chat_btn.config(state=tk.NORMAL)
            self.status_var.set(f"已连接到 {server_info} - 房间: {room}")
            self.add_message("系统", f"成功连接到房间 {room}", "system")

        except Exception as e:
            messagebox.showerror("连接错误", f"无法连接到服务器: {e}")
            self.connected = False

    def disconnect_from_server(self):
        """断开服务器连接"""
        if self.connected and self.socket:
            try:
                leave_message = {
                    'type': 'leave',
                    'username': self.username
                }
                self.send_to_server(leave_message)
            except:
                pass

            self.socket.close()
            self.connected = False

            # 更新UI
            self.connect_btn.config(text="连接")
            self.refresh_users_btn.config(state=tk.DISABLED)
            self.save_chat_btn.config(state=tk.DISABLED)
            self.status_var.set("未连接")
            self.user_listbox.delete(0, tk.END)
            self.user_count_var.set("在线用户: 0")
            self.add_message("系统", "已断开连接", "system")

    def send_to_server(self, message):
        """向服务器发送消息"""
        if not self.connected or not self.socket:
            return

        try:
            data = json.dumps(message, ensure_ascii=False)
            data_bytes = data.encode('utf-8')

            length_bytes = len(data_bytes).to_bytes(4, byteorder='big')
            self.socket.send(length_bytes + data_bytes)

        except Exception as e:
            print(f"发送消息失败: {e}")
            self.disconnect_from_server()

    def receive_full_message(self):
        """接收完整消息，支持大文件传输"""
        try:
            # 先接收消息长度
            length_data = b''
            while len(length_data) < 4:
                chunk = self.socket.recv(4 - len(length_data))
                if not chunk:
                    return None
                length_data += chunk

            message_length = int.from_bytes(length_data, byteorder='big')

            # 接收完整消息
            message_data = b''
            while len(message_data) < message_length:
                chunk = self.socket.recv(min(4096, message_length - len(message_data)))
                if not chunk:
                    return None
                message_data += chunk

            return message_data.decode('utf-8')
        except Exception as e:
            print(f"接收消息错误: {e}")
            return None

    def receive_messages(self):
        """接收服务器消息"""
        while self.connected:
            try:
                data = self.receive_full_message()
                if not data:
                    break

                message = json.loads(data)
                self.process_received_message(message)

            except Exception as e:
                if self.connected:
                    print(f"接收消息错误: {e}")
                break

        self.connected = False

    def process_received_message(self, message):
        """处理接收到的消息"""
        msg_type = message.get('type')

        if msg_type == 'chat':
            self.add_message(
                message.get('username'),
                message.get('message'),
                'chat',
                message.get('timestamp')
            )
        elif msg_type == 'image':
            self.add_image_message(
                message.get('username'),
                message.get('image_data'),
                message.get('filename'),
                message.get('timestamp')
            )
        elif msg_type == 'emoji':
            self.add_message(
                message.get('username'),
                message.get('emoji'),
                'emoji',
                message.get('timestamp')
            )
        elif msg_type == 'system':
            self.add_message(
                "系统",
                message.get('message'),
                'system',
                message.get('timestamp')
            )
        elif msg_type == 'user_list':
            self.update_user_list(message.get('users', []))
        elif msg_type == 'private_chat':
            self.add_private_message(
                message.get('username'),
                message.get('message'),
                'private_chat',
                message.get('timestamp'),
                is_received=True
            )
        elif msg_type == 'private_image':
            self.add_private_image_message(
                message.get('username'),
                message.get('image_data'),
                message.get('filename'),
                message.get('timestamp'),
                is_received=True
            )
        elif msg_type == 'private_emoji':
            self.add_private_message(
                message.get('username'),
                message.get('emoji'),
                'private_emoji',
                message.get('timestamp'),
                is_received=True
            )
        elif msg_type == 'private_chat_sent':
            self.add_private_message(
                message.get('username'),
                message.get('message'),
                'private_chat',
                message.get('timestamp'),
                is_received=False,
                target_user=message.get('target_user')
            )
        elif msg_type == 'private_image_sent':
            self.add_message(
                "系统",
                f"图片已发送给 {message.get('target_user')}",
                'system',
                message.get('timestamp')
            )
        elif msg_type == 'private_emoji_sent':
            self.add_private_message(
                message.get('username'),
                message.get('emoji'),
                'private_emoji',
                message.get('timestamp'),
                is_received=False,
                target_user=message.get('target_user')
            )

    def add_message(self, username, message, msg_type, timestamp=None):
        """添加消息到聊天区域"""
        if not timestamp:
            timestamp = datetime.now().strftime('%H:%M:%S')

        self.message_area.config(state=tk.NORMAL)

        if msg_type == 'system':
            self.message_area.insert(tk.END, f"[{timestamp}] {message}\n")
            self.message_area.tag_add("system", "end-2l", "end-1l")
            self.message_area.tag_config("system", foreground="gray")
        elif msg_type == 'emoji':
            self.message_area.insert(tk.END, f"[{timestamp}] {username}: ")

            if message in self.emoji_images:
                try:
                    self.message_area.image_create(tk.END, image=self.emoji_images[message])
                    print(f"[v0] 成功显示表情包图片: {message}")
                except Exception as e:
                    print(f"[v0] 表情包图片显示失败: {message}, 错误: {e}")
                    # 回退到文字显示
                    self.message_area.insert(tk.END, f"[{message}]")
            else:
                print(f"[v0] 表情包图片不存在: {message}")
                # 回退到文字显示
                self.message_area.insert(tk.END, f"{message}")

            self.message_area.insert(tk.END, "\n")
        else:
            self.message_area.insert(tk.END, f"[{timestamp}] {username}: {message}\n")

        self.message_area.config(state=tk.DISABLED)
        self.message_area.see(tk.END)

    def add_image_message(self, username, image_data, filename, timestamp):
        """添加图片消息"""
        try:
            # 解码base64图片数据
            image_bytes = base64.b64decode(image_data)
            image = Image.open(io.BytesIO(image_bytes))

            # 调整图片大小用于显示
            display_image = image.copy()
            display_image.thumbnail((200, 200), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(display_image)

            self.message_area.config(state=tk.NORMAL)
            self.message_area.insert(tk.END, f"[{timestamp}] {username} 发送了图片 {filename}:\n")

            # 获取当前插入位置
            current_pos = self.message_area.index(tk.INSERT)

            # 插入图片
            self.message_area.image_create(tk.END, image=photo)

            # 获取图片插入后的位置
            end_pos = self.message_area.index(tk.INSERT)

            # 为图片区域创建标签和绑定点击事件
            tag_name = f"image_{len(self.chat_images)}"
            self.message_area.tag_add(tag_name, current_pos, end_pos)

            # 绑定鼠标事件来实现悬停效果和点击功能
            def on_enter(event):
                try:
                    self.message_area.tag_config(tag_name, background="lightblue")
                except:
                    pass

            def on_leave(event):
                try:
                    self.message_area.tag_config(tag_name, background="")
                except:
                    pass

            def on_click(event):
                self.create_image_viewer(image_data, filename)

            # 绑定事件
            self.message_area.tag_bind(tag_name, "<Enter>", on_enter)
            self.message_area.tag_bind(tag_name, "<Leave>", on_leave)
            self.message_area.tag_bind(tag_name, "<Button-1>", on_click)

            # 添加提示文本
            self.message_area.insert(tk.END, " 📷 点击查看大图")
            self.message_area.insert(tk.END, "\n")

            self.message_area.config(state=tk.DISABLED)
            self.message_area.see(tk.END)

            self.chat_images.append({
                'data': image_data,
                'filename': filename,
                'photo': photo  # 保持引用防止垃圾回收
            })

        except Exception as e:
            self.message_area.config(state=tk.NORMAL)
            self.message_area.insert(tk.END, f"[{timestamp}] {username} 发送了图片 {filename}\n")
            self.message_area.insert(tk.END, f"[{timestamp}] 无法显示图片: {str(e)}\n")
            self.message_area.config(state=tk.DISABLED)
            self.message_area.see(tk.END)
            print(f"[v0] 图片显示错误: {e}")

    def update_user_list(self, users):
        """更新用户列表"""
        self.user_listbox.delete(0, tk.END)
        for user in users:
            self.user_listbox.insert(tk.END, user)

        self.user_count_var.set(f"在线用户: {len(users)}")

        if self.chat_mode.get() == "private":
            self.update_private_target_list()

    def send_message(self, event=None):
        """发送文字消息"""
        if not self.connected:
            messagebox.showwarning("警告", "请先连接到服务器")
            return

        message = self.message_entry.get().strip()
        if not message:
            return

        if self.chat_mode.get() == "private":
            target_user = self.private_target_var.get()
            if not target_user:
                messagebox.showwarning("警告", "请选择私聊对象")
                return
            chat_message = {
                'type': 'private_chat',
                'message': message,
                'target_user': target_user
            }
        else:
            chat_message = {
                'type': 'chat',
                'message': message
            }
        self.send_to_server(chat_message)
        self.message_entry.delete(0, tk.END)

    def send_image(self):
        """发送图片"""
        if not self.connected:
            messagebox.showwarning("警告", "请先连接到服务器")
            return

        file_path = filedialog.askopenfilename(
            title="选择图片",
            filetypes=[
                ("图片文件", "*.png *.jpg *.jpeg *.gif *.bmp"),
                ("所有文件", "*.*")
            ]
        )

        if not file_path:
            return

        try:
            # 检查文件大小（限制5MB）
            file_size = os.path.getsize(file_path)
            if file_size > 5 * 1024 * 1024:  # 5MB
                messagebox.showerror("错误", "图片文件太大，请选择小于5MB的图片")
                return

            # 使用PIL压缩图片
            with Image.open(file_path) as img:
                # 转换为RGB模式（处理RGBA等格式）
                if img.mode in ('RGBA', 'LA', 'P'):
                    img = img.convert('RGB')

                # 调整图片大小（最大800x600）
                img.thumbnail((800, 600), Image.Resampling.LANCZOS)

                # 保存到内存
                img_buffer = io.BytesIO()
                img.save(img_buffer, format='JPEG', quality=85, optimize=True, icc_profile=None)
                img_buffer.seek(0)

                # 编码为base64
                image_data = base64.b64encode(img_buffer.getvalue()).decode('utf-8')

            filename = os.path.basename(file_path)
            if self.chat_mode.get() == "private":
                target_user = self.private_target_var.get()
                if not target_user:
                    messagebox.showwarning("警告", "请选择私聊对象")
                    return
                image_message = {
                    'type': 'private_image',
                    'image_data': image_data,
                    'filename': filename,
                    'target_user': target_user
                }
            else:
                image_message = {
                    'type': 'image',
                    'image_data': image_data,
                    'filename': filename
                }

            # 显示发送状态
            self.add_message("系统", f"正在发送图片 {filename}...", "system")
            self.send_to_server(image_message)

        except Exception as e:
            messagebox.showerror("错误", f"无法发送图片: {e}")
            print(f"图片发送错误详情: {e}")

    def send_emoji(self, emoji):
        """发送表情包"""
        if not self.connected:
            messagebox.showwarning("警告", "请先连接到服务器")
            return

        if self.chat_mode.get() == "private":
            target_user = self.private_target_var.get()
            if not target_user:
                messagebox.showwarning("警告", "请选择私聊对象")
                return
            emoji_message = {
                'type': 'private_emoji',
                'emoji': emoji,
                'target_user': target_user
            }
        else:
            emoji_message = {
                'type': 'emoji',
                'emoji': emoji
            }
        self.send_to_server(emoji_message)

    def on_closing(self):
        """窗口关闭事件"""
        if self.connected:
            self.disconnect_from_server()
        self.root.destroy()

    def run(self):
        """运行客户端"""
        self.root.mainloop()

    def create_image_viewer(self, image_data, filename):
        """创建图片查看窗口"""
        try:
            # 创建新窗口
            viewer = tk.Toplevel(self.root)
            viewer.title(f"查看图片 - {filename}")
            viewer.geometry("600x500")
            viewer.transient(self.root)
            viewer.grab_set()

            # 解码图片数据
            image_bytes = base64.b64decode(image_data)
            image = Image.open(io.BytesIO(image_bytes))

            # 获取原始图片尺寸
            original_width, original_height = image.size

            # 创建滚动区域
            canvas = tk.Canvas(viewer, bg='white')
            scrollbar_v = ttk.Scrollbar(viewer, orient="vertical", command=canvas.yview)
            scrollbar_h = ttk.Scrollbar(viewer, orient="horizontal", command=canvas.xview)
            scrollable_frame = ttk.Frame(canvas)

            scrollable_frame.bind(
                "<Configure>",
                lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
            )

            canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
            canvas.configure(yscrollcommand=scrollbar_v.set, xscrollcommand=scrollbar_h.set)

            # 布局滚动组件
            canvas.pack(side="left", fill="both", expand=True)
            scrollbar_v.pack(side="right", fill="y")
            scrollbar_h.pack(side="bottom", fill="x")

            # 创建控制面板
            control_frame = ttk.Frame(viewer)
            control_frame.pack(side="bottom", fill="x", padx=5, pady=5)

            # 缩放控制
            scale_var = tk.DoubleVar(value=1.0)
            ttk.Label(control_frame, text="缩放:").pack(side="left")

            def update_image_scale(value):
                scale = float(value)
                new_width = int(original_width * scale)
                new_height = int(original_height * scale)

                if new_width > 0 and new_height > 0:
                    resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
                    photo = ImageTk.PhotoImage(resized_image)

                    # 清除之前的内容
                    for widget in scrollable_frame.winfo_children():
                        widget.destroy()

                    # 显示新图片
                    img_label = ttk.Label(scrollable_frame, image=photo)
                    img_label.image = photo  # 保持引用
                    img_label.pack()

                    # 更新画布滚动区域
                    scrollable_frame.update_idletasks()
                    canvas.configure(scrollregion=canvas.bbox("all"))

            scale_slider = ttk.Scale(
                control_frame,
                from_=0.1,
                to=3.0,
                variable=scale_var,
                orient="horizontal",
                length=200,
                command=update_image_scale
            )
            scale_slider.pack(side="left", padx=5)

            # 预设缩放按钮
            ttk.Button(control_frame, text="适合窗口",
                       command=lambda: self.fit_image_to_window(viewer, image, scale_var, update_image_scale)).pack(
                side="left", padx=5)
            ttk.Button(control_frame, text="原始大小",
                       command=lambda: scale_var.set(1.0) or update_image_scale(1.0)).pack(side="left", padx=5)

            # 保存按钮
            ttk.Button(control_frame, text="保存图片",
                       command=lambda: self.save_image(image, filename)).pack(side="right", padx=5)

            # 图片信息
            info_text = f"尺寸: {original_width}x{original_height} | 文件: {filename}"
            ttk.Label(control_frame, text=info_text).pack(side="right", padx=10)

            # 初始显示
            update_image_scale(1.0)

            # 键盘快捷键
            def on_key(event):
                if event.keysym == 'Escape':
                    viewer.destroy()
                elif event.keysym == 'plus' or event.keysym == 'equal':
                    current = scale_var.get()
                    scale_var.set(min(3.0, current * 1.2))
                    update_image_scale(scale_var.get())
                elif event.keysym == 'minus':
                    current = scale_var.get()
                    scale_var.set(max(0.1, current / 1.2))
                    update_image_scale(scale_var.get())

            viewer.bind('<Key>', on_key)
            viewer.focus_set()

        except Exception as e:
            messagebox.showerror("错误", f"无法打开图片查看器: {e}")

    def fit_image_to_window(self, viewer, image, scale_var, update_callback):
        """调整图片适合窗口大小"""
        try:
            # 获取窗口大小（减去控制面板高度）
            viewer.update_idletasks()
            window_width = viewer.winfo_width() - 50  # 留边距
            window_height = viewer.winfo_height() - 100  # 减去控制面板高度

            # 计算缩放比例
            img_width, img_height = image.size
            scale_x = window_width / img_width
            scale_y = window_height / img_height
            scale = min(scale_x, scale_y, 3.0)  # 最大不超过3倍

            scale_var.set(scale)
            update_callback(scale)
        except Exception as e:
            print(f"适合窗口失败: {e}")

    def save_image(self, image, filename):
        """保存图片到本地"""
        try:
            file_path = filedialog.asksaveasfilename(
                title="保存图片",
                defaultextension=".jpg",
                initialfile=filename ,
                filetypes=[
                    ("JPEG图片", "*.jpg"),
                    ("PNG图片", "*.png"),
                    ("所有文件", "*.*")
                ]
            )

            if file_path:
                # 根据文件扩展名保存
                if file_path.lower().endswith('.png'):
                    image.save(file_path, 'PNG')
                else:
                    # 转换为RGB模式保存为JPEG
                    if image.mode in ('RGBA', 'LA', 'P'):
                        image = image.convert('RGB')
                    image.save(file_path, 'JPEG', quality=95)

                messagebox.showinfo("成功", f"图片已保存到: {file_path}")
        except Exception as e:
            messagebox.showerror("错误", f"保存图片失败: {e}")

    def refresh_user_list(self):
        """刷新用户列表"""
        if not self.connected:
            messagebox.showwarning("警告", "请先连接到服务器")
            return

        refresh_message = {
            'type': 'refresh_users'
        }
        self.send_to_server(refresh_message)

    def on_chat_mode_change(self):
        """聊天模式切换事件"""
        mode = self.chat_mode.get()
        if mode == "private":
            self.private_target_frame.pack(side=tk.LEFT, padx=(20, 0))
            self.update_private_target_list()
            target = self.private_target_var.get()
            if target:
                self.chat_status_var.set(f"私聊模式 - 与 {target}")
            else:
                self.chat_status_var.set("私聊模式 - 请选择对象")
        else:
            self.private_target_frame.pack_forget()
            self.chat_status_var.set("群聊模式")

    def on_user_double_click(self, event):
        """用户列表双击事件 - 快速切换到私聊模式"""
        selection = self.user_listbox.curselection()
        if selection:
            selected_user = self.user_listbox.get(selection[0])
            if selected_user != self.username:  # 不能和自己私聊
                self.chat_mode.set("private")
                self.on_chat_mode_change()
                self.private_target_var.set(selected_user)
                self.chat_status_var.set(f"私聊模式 - 与 {selected_user}")
                self.add_message("系统", f"已切换到与 {selected_user} 的私聊模式", "system")

    def update_private_target_list(self):
        """更新私聊目标用户列表"""
        current_users = []
        for i in range(self.user_listbox.size()):
            user = self.user_listbox.get(i)
            if user != self.username:  # 排除自己
                current_users.append(user)

        self.private_target_combo['values'] = current_users

        # 如果当前选择的用户不在列表中，清空选择
        current_target = self.private_target_var.get()
        if current_target and current_target not in current_users:
            self.private_target_var.set("")
            self.chat_status_var.set("私聊模式 - 请选择对象")

    def save_chat_history(self):
        """保存聊天记录到本地"""
        if not self.connected:
            messagebox.showwarning("警告", "请先连接到服务器")
            return

        try:
            # 获取聊天内容
            chat_content = self.message_area.get("1.0", tk.END)

            if not chat_content.strip():
                messagebox.showinfo("提示", "没有聊天记录可保存")
                return

            # 生成文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            default_filename = f"聊天记录_{self.room}_{timestamp}.txt"

            # 选择保存位置
            file_path = filedialog.asksaveasfilename(
                title="保存聊天记录",
                defaultextension=".txt",
                initialfile=default_filename,

                filetypes=[
                    ("文本文件", "*.txt"),
                    ("HTML文件", "*.html"),
                    ("所有文件", "*.*")
                ]
            )

            if not file_path:
                return

            # 根据文件扩展名选择保存格式
            if file_path.lower().endswith('.html'):
                self.save_as_html(file_path, chat_content)
            else:
                self.save_as_text(file_path, chat_content)

            messagebox.showinfo("成功", f"聊天记录已保存到: {file_path}")

        except Exception as e:
            messagebox.showerror("错误", f"保存聊天记录失败: {e}")

    def save_as_text(self, file_path, content):
        """保存为文本格式"""
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(f"聊天记录 - 房间: {self.room}\n")
            f.write(f"保存时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write("=" * 50 + "\n\n")
            f.write(content)

    def save_as_html(self, file_path, content):
        """保存为HTML格式"""
        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>聊天记录 - {self.room}</title>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 20px; }}
        .header {{ background-color: #f0f0f0; padding: 10px; border-radius: 5px; margin-bottom: 20px; }}
        .message {{ margin: 5px 0; padding: 5px; }}
        .system {{ color: #666; font-style: italic; }}
        .private {{ color: #0066cc; font-style: italic; }}
        .timestamp {{ color: #999; font-size: 0.9em; }}
    </style>
</head>
<body>
    <div class="header">
        <h2>聊天记录 - 房间: {self.room}</h2>
        <p>保存时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
    </div>
    <div class="content">
        <pre>{content}</pre>
    </div>
</body>
</html>
"""
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(html_content)

    def add_private_message(self, username, message, msg_type, timestamp, is_received=True, target_user=None):
        """添加私聊消息到聊天区域"""
        if not timestamp:
            timestamp = datetime.now().strftime('%H:%M:%S')

        self.message_area.config(state=tk.NORMAL)

        if is_received:
            prefix = f"[{timestamp}] [私聊] {username} -> 我: "
        else:
            prefix = f"[{timestamp}] [私聊] 我 -> {target_user}: "

        if msg_type == 'private_emoji':
            self.message_area.insert(tk.END, prefix)

            if message in self.emoji_images:
                try:
                    self.message_area.image_create(tk.END, image=self.emoji_images[message])
                except Exception as e:
                    self.message_area.insert(tk.END, f"{message}")
            else:
                self.message_area.insert(tk.END, f"{message}")

            self.message_area.insert(tk.END, "\n")
        else:
            self.message_area.insert(tk.END, f"{prefix}{message}\n")

        # 为私聊消息添加特殊样式
        self.message_area.tag_add("private", "end-2l", "end-1l")
        self.message_area.tag_config("private", foreground="blue", font=("Arial", 10, "italic"))

        self.message_area.config(state=tk.DISABLED)
        self.message_area.see(tk.END)

    def add_private_image_message(self, username, image_data, filename, timestamp, is_received=True):
        """添加私聊图片消息"""
        try:
            # 解码base64图片数据
            image_bytes = base64.b64decode(image_data)
            image = Image.open(io.BytesIO(image_bytes))

            # 调整图片大小用于显示
            display_image = image.copy()
            display_image.thumbnail((200, 200), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(display_image)

            self.message_area.config(state=tk.NORMAL)

            if is_received:
                prefix = f"[{timestamp}] [私聊] {username} -> 我 发送了图片 {filename}:\n"
            else:
                prefix = f"[{timestamp}] [私聊] 我 发送了图片 {filename}:\n"

            self.message_area.insert(tk.END, prefix)

            # 获取当前插入位置
            current_pos = self.message_area.index(tk.INSERT)

            # 插入图片
            self.message_area.image_create(tk.END, image=photo)

            # 获取图片插入后的位置
            end_pos = self.message_area.index(tk.INSERT)

            # 为图片区域创建标签和绑定点击事件
            tag_name = f"private_image_{len(self.chat_images)}"
            self.message_area.tag_add(tag_name, current_pos, end_pos)

            # 绑定鼠标事件
            def on_enter(event):
                try:
                    self.message_area.tag_config(tag_name, background="lightblue")
                except:
                    pass

            def on_leave(event):
                try:
                    self.message_area.tag_config(tag_name, background="")
                except:
                    pass

            def on_click(event):
                self.create_image_viewer(image_data, filename)

            self.message_area.tag_bind(tag_name, "<Enter>", on_enter)
            self.message_area.tag_bind(tag_name, "<Leave>", on_leave)
            self.message_area.tag_bind(tag_name, "<Button-1>", on_click)

            self.message_area.insert(tk.END, " 📷 点击查看大图")
            self.message_area.insert(tk.END, "\n")

            # 为私聊图片消息添加特殊样式
            self.message_area.tag_add("private", "end-3l", "end-1l")
            self.message_area.tag_config("private", foreground="blue", font=("Arial", 10, "italic"))

            self.message_area.config(state=tk.DISABLED)
            self.message_area.see(tk.END)

            self.chat_images.append({
                'data': image_data,
                'filename': filename,
                'photo': photo
            })

        except Exception as e:
            self.message_area.config(state=tk.NORMAL)
            if is_received:
                prefix = f"[{timestamp}] [私聊] {username} -> 我 发送了图片 {filename}\n"
            else:
                prefix = f"[{timestamp}] [私聊] 我 发送了图片 {filename}\n"
            self.message_area.insert(tk.END, prefix)
            self.message_area.insert(tk.END, f"[{timestamp}] 无法显示图片: {str(e)}\n")
            self.message_area.config(state=tk.DISABLED)
            self.message_area.see(tk.END)


if __name__ == "__main__":
    client = ChatClient()
    client.run()
